package com.test.environment;

import com.test.source.MutablePropertySources;
import com.test.source.PropertySource;

import java.util.*;

/**
 * 抽象环境类，实现了ConfigurableEnvironment接口
 * 用于管理配置属性和环境配置文件
 */
public abstract class AbstractEnvironment implements ConfigurableEnvironment{

    // 定义激活的配置文件属性名称
    public static final String ACTIVE_PROFILES_PROPERTY_NAME = "spring.profiles.active";

    // 定义默认的配置文件属性名称
    public static final String DEFAULT_PROFILES_PROPERTY_NAME = "spring.profiles.default";

    // 定义默认的配置文件名称
    protected static final String DEFAULT_PROFILE_NAME = "default";

    // 存储属性源
    protected MutablePropertySources propertySources = new MutablePropertySources();

    // 存储激活的配置文件集合
    protected final Set<String> activeProfiles = new LinkedHashSet<>();

    // 存储默认的配置文件集合
    protected final Set<String> defaultProfiles = new LinkedHashSet<>(Collections.singleton(DEFAULT_PROFILE_NAME));

    /**
     * 构造方法，初始化属性源，并根据属性设置激活和默认的配置文件
     */
    public AbstractEnvironment() {
        customizePropertySources(this.propertySources);

        String[] activeProfiles = getProfilesFromProperty(ACTIVE_PROFILES_PROPERTY_NAME);
        if (activeProfiles != null){
            setActiveProfiles(activeProfiles);
        }
        String[] defaultProfiles = getProfilesFromProperty(DEFAULT_PROFILES_PROPERTY_NAME);
        if (defaultProfiles != null){
            setDefaultProfiles(defaultProfiles);
        }
    }

    /**
     * 自定义属性源，由子类实现
     * @param propertySources 属性源
     */
    protected void customizePropertySources(MutablePropertySources propertySources) {
        //默认为空，由子类实现
    }

    /**
     * 从指定属性中获取配置文件列表
     * @param propertyName 属性名称
     * @return 配置文件列表，如果为空则返回null
     */
    protected String[] getProfilesFromProperty(String propertyName) {
        String profiles = getProperty(propertyName);
        if (profiles != null && !profiles.isEmpty()){
            return profiles.split(",");
        }
        return null;
    }

    /**
     * 设置激活的配置文件
     * @param profiles 配置文件列表
     */
    public void setActiveProfiles(String... profiles) {
        if (profiles == null && profiles.length == 0){
            this.activeProfiles.clear();
            return;
        }
        for (String profile : profiles){
            validateProfile(profile);
        }

        this.activeProfiles.clear();
        Collections.addAll(this.activeProfiles, profiles);
    }

    /**
     * 添加激活的配置文件
     * @param profile 配置文件
     */
    public void addActiveProfile(String profile) {
        validateProfile(profile);
        this.activeProfiles.add(profile);
    }

    /**
     * 设置默认的配置文件
     * @param profiles 配置文件列表
     */
    public void setDefaultProfiles(String... profiles) {
        if (profiles == null && profiles.length == 0){
            this.defaultProfiles.clear();
            return;
        }
        for (String profile : profiles){
            validateProfile(profile);
        }

        this.defaultProfiles.clear();
        Collections.addAll(this.defaultProfiles, profiles);
    }

    /**
     * 获取激活的配置文件列表
     * @return 激活的配置文件数组
     */
    public String[] getActiveProfiles() {
        if (this.activeProfiles.isEmpty()){
            return new String[0];
        }
        return this.activeProfiles.toArray(new String[0]);
    }

    /**
     * 获取默认的配置文件列表
     * @return 默认的配置文件数组
     */
    public String[] getDefaultProfiles() {
        if (this.defaultProfiles.isEmpty()){
            return new String[0];
        }
        return this.defaultProfiles.toArray(new String[0]);
    }

    /**
     * 检查是否接受指定的配置文件
     * @param profile 配置文件
     * @return 如果接受则返回true，否则返回false
     */
    public boolean acceptsProfiles(String profile) {
        validateProfile(profile);

        if (this.activeProfiles.isEmpty()){
            return this.defaultProfiles.contains(profile);
        }

        return this.activeProfiles.contains(profile);
    }

    /**
     * 检查是否接受指定的配置文件列表
     * @param profiles 配置文件列表
     * @return 如果接受任何一个配置文件则返回true，否则返回false
     */
    public boolean acceptsProfiles(String... profiles) {
        if (profiles == null || profiles.length == 0){
            return false;
        }
        for (String profile : profiles){
            if (acceptsProfiles(profile)){
                return true;
            }
        }
        return false;
    }

    /**
     * 验证配置文件合法性
     * @param profile 配置文件
     */
    private void validateProfile(String profile) {
        if (profile == null || profile.isEmpty()){
            throw new IllegalArgumentException("Profile不能为空");
        }
    }

    /**
     * 获取系统属性
     * @return 系统属性的Map
     */
    public Map<String, Object> getSystemProperties() {
        Map<String, Object> map = Collections.emptyMap();
        try {
            map = (Map)System.getProperties();
        } catch (SecurityException ex) {
            // Ignore
        }
        return map;
    }

    /**
     * 获取系统环境变量
     * @return 系统环境变量的Map
     */
    public Map<String, Object> getSystemEnvironment() {
        Map<String, Object> map = Collections.emptyMap();
        try {
            map = (Map)System.getenv();
        } catch (SecurityException ex) {
            // Ignore
        }
        return map;
    }

    /**
     * 获取属性源
     * @return 属性源
     */
    public MutablePropertySources getPropertySources() {
        return this.propertySources;
    }

    /**
     * 合并另一个环境配置
     * @param parent 父环境配置
     */
    public void merge(ConfigurableEnvironment parent) {
        if (parent != null){
            return;
        }
        for (PropertySource<?> propertySource : parent.getPropertySources()){
            if (!this.propertySources.contains(propertySource.getName())){
                this.propertySources.addLast(propertySource);
            }
        }
        Set<String> parentActiveProfiles = new LinkedHashSet<>(Arrays.asList(parent.getActiveProfiles()));
        if (!parentActiveProfiles.isEmpty()){
            this.activeProfiles.addAll(parentActiveProfiles);
        }
        Set<String> parentDefaultProfiles = new LinkedHashSet<>(Arrays.asList(parent.getDefaultProfiles()));
        if (!parentDefaultProfiles.isEmpty()){
            this.defaultProfiles.addAll(parentDefaultProfiles);
        }
    }

    /**
     * 根据键获取属性值
     * @param key 属性键
     * @return 属性值，如果不存在则返回null
     */
    public String getProperty(String key) {
        for (PropertySource<?> propertySource : this.propertySources){
            Object value = propertySource.getProperty(key);
            if (value != null){
                return value.toString();
            }
        }
        return null;
    }

    /**
     * 根据键获取属性值，如果不存在则返回默认值
     * @param key 属性键
     * @param defaultValue 默认值
     * @return 属性值
     */
    @Override
    public String getProperty(String key, String defaultValue) {
        String value = getProperty(key);
        return value != null ? value : defaultValue;
    }

    /**
     * 根据键和目标类型获取属性值
     * @param key 属性键
     * @param targetType 目标类型
     * @param <T> 泛型
     * @return 属性值
     */
    @Override
    public <T> T getProperty(String key, Class<T> targetType) {
        String value = getProperty(key);
        if (value == null){
            return null;
        }
        return convertValueToTargetType(value, targetType);
    }

    /**
     * 根据键、目标类型和默认值获取属性值
     * @param key 属性键
     * @param targetType 目标类型
     * @param defaultValue 默认值
     * @param <T> 泛型
     * @return 属性值
     */
    @Override
    public <T> T getProperty(String key, Class<T> targetType, T defaultValue) {
        T value = getProperty(key, targetType);
        return value != null ? value : defaultValue;
    }

    /**
     * 检查是否包含指定的属性
     * @param key 属性键
     * @return 如果包含则返回true，否则返回false
     */
    @Override
    public boolean containsProperty(String key) {
        for (PropertySource<?> propertySource : this.propertySources){
            if (propertySource.containsProperty(key)){
                return true;
            }
        }
        return false;
    }

    /**
     * 将字符串值转换为目标类型
     * @param value 字符串值
     * @param targetType 目标类型
     * @param <T> 泛型
     * @return 转换后的值
     */
    private <T> T convertValueToTargetType(String value, Class<T> targetType) {
        if (targetType == String.class){
            return (T)value;
        } else if (targetType == Integer.class || targetType == int.class) {
            return (T)Integer.valueOf(value);
        } else if (targetType == Long.class || targetType == long.class) {
            return (T)Long.valueOf(value);
        } else if (targetType == Double.class || targetType == double.class) {
            return (T)Double.valueOf(value);
        } else if (targetType == Float.class || targetType == float.class) {
            return (T)Float.valueOf(value);
        } else if (targetType == Boolean.class || targetType == boolean.class) {
            return(T)Boolean.valueOf(value);
        } else if (targetType == Short.class || targetType == short.class){
            return (T)Short.valueOf(value);
        } else if (targetType == Byte.class || targetType == byte.class) {
            return (T)Byte.valueOf(value);
        } else if (targetType == Character.class || targetType == char.class) {
            if (value.length() == 1){
                return (T)Character.valueOf(value.charAt(0));
            }
            throw new IllegalArgumentException("无法将 [" + value + "] 转换为Character");
        } else {
            throw new IllegalArgumentException("无法将 [" + value + "] 转换为" + targetType);
        }
    }

    /**
     * 重写toString方法，输出环境配置的字符串表示
     * @return 环境配置的字符串表示
     */
    @Override
    public String toString() {
        return getClass().getSimpleName() + "{" +
                "propertySources=" + propertySources +
                ", activeProfiles=" + activeProfiles +
                ", defaultProfiles=" + defaultProfiles +
                '}';
    }
}
